/**
  ******************************************************************************
  * @file    data_convert.c
  * @author  ashuai0110
  * @version V2.3
  * @date    2024-07-01
  * @brief   数据转换方法集合
  *
  ******************************************************************************
  * @attention
  *
  * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
  * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
  *
  * Change Logs:
  * Date          Author        Notes
  * 2023-09-19    ashuai0110    完成基本内容
  * 2023-12-11    ashuai0110    新增conv_complement_code_to_dec函数
  * 
  ******************************************************************************
  */

/* 包含头文件-----------------------------------------------------------------*/
#include "data_convert.h"

/**
 * @addtogroup modules
 * @{
 */

/**
 * @defgroup data_convert data_convert
 * @{
 */

/* 私有宏定义-----------------------------------------------------------------*/
/**
 * @defgroup data_convert_local_macros data convert local macros
 * @{
 */

/**
 * @defgroup data_convert_check_parameters_validity data convert check parameters validity
 * @{
 */
/* 十进制字符串转十进制整数的长度有效性检查 */
#define IS_VALID_DEC_DEC_LENGTH(x)                                            \
(       (x) <= 11)

/* 十六进制字符串转十进制整数的长度有效性检查 */
#define IS_VALID_HEX_DEC_LENGTH(x)                                            \
(       (x) <= 8)

/* 补码转十进制整数的位数有效性检查 */
#define IS_VALID_COMP_DEC_BIT_NUM(x)                                          \
(       (x) <= 32)
/**
 * @}
 */

/**
 * @}
 */

/* 私有类型定义---------------------------------------------------------------*/

/* 私有变量-------------------------------------------------------------------*/

/* 全局变量-------------------------------------------------------------------*/

/* 私有函数原型---------------------------------------------------------------*/
/**
 * @defgroup data_convert_local_functions data convert local functions
 * @{
 */

/**
  * @brief  conv_str_dec_to_dec()函数的内部方法,描述同此函数
  */
static int conv_str_dec_to_dec_method(char *pSrc, uint8_t len)
{
    uint8_t i = 0, j = 0;
    int ret = 0, tmp = 0;

    for(i = 0; i < len; i++)
    {
        /* 超出十进制字符范围则return */
        if(pSrc[i] < '0' || pSrc[i] > '9')
        {
            return 0;
        }
        tmp = pSrc[i] - '0'; /* 减去字符'0'即是整数值 */
        j = len - 1 - i;
        while(j--)
        {
            tmp = (tmp << 3) + (tmp << 1); /* 根据当前字符位置乘以10 例:共3个字符,当前字符是第1个,则乘以两次10 */
        }
        ret += tmp; /* 累加结果 */
    }
    
    return ret;
}

/**
 * @}
 */

/**
 * @defgroup data_convert_global_functions data convert global functions
 * @{
 */

/**
  * @brief  以指定分割符分割字符串
  *
  * @note   pSrc = “cmd 1 2 3”, 空格分割
  *         pBuf[0] = “cmd”
  *         pBuf[1] = “1”
  *         pBuf[2] = “2”
  *         pBuf[3] = “3”
  *
  * @param  pBuf : 分解后存放的缓存区
  *
  * @param  pSrc : 源数据
  *
  * @param  flg  : 单字节分割符
  *
  * @param  num  : 期望分割数量
  *
  * @retval 0:错误  !0:实际分割数量
  */
uint32_t conv_str_split(char *pBuf[], char *pSrc, char flg, uint32_t num)
{
    uint32_t cnt = 0;
    
    ASSERT_PARAM(IS_VALID_POINT(pBuf));
    ASSERT_PARAM(IS_VALID_POINT(pSrc));
    
    /* 缓存区先存放第一个字符串首地址 */
    pBuf[cnt++] = pSrc;
    while(1)
    {
        /* 若当前字符与参数flg相同 */
        if(*pSrc == flg)
        {
            *pSrc = '\0'; /* 当前字符改为'\0' 代表字符串到此结束 */
            /* 若分割数量达到参数num则break */
            if(cnt >= num)
            {
                break;
            }
            pBuf[cnt++] = pSrc + 1; /* 缓存区存放下一个字符串首地址 */
        } /* 若当前字符与结束符'\r' '\n' '\0'相同则break, 结束符可自定义修改 */
        else if(*pSrc == '\r' || *pSrc == '\n' || *pSrc == '\0')
        {
            *pSrc = '\0';
            break;
        }
        pSrc++; /* 当前字符地址自增 */
    }
    
    return cnt;
}

/**
  * @brief  十进制字符串转十进制整数
  *
  * @note   可以转换负数
  *
  * @param  pSrc : 源字符串
  *
  * @param  len  : 转换数量,填0内部使用strlen()判断长度
  *
  * @retval 返回转换后的十进制整数
  */
int conv_str_dec_to_dec(char *pSrc, uint8_t len)
{
    int dec;
    
    if(len == 0)
    {
        len = strlen(pSrc); /* 参数len是0则使用strlen获取长度 */
    }
    
    ASSERT_PARAM(IS_VALID_POINT(pSrc));
    ASSERT_PARAM(IS_VALID_DEC_DEC_LENGTH(len));
    
    /* 首个字符是-则表示是负数 */
    if(strncmp(pSrc, "-", 1) == 0)
    {
        dec = 0 - conv_str_dec_to_dec_method(pSrc + 1, len - 1);
    } /* 首个字符不是-则表示是正数 */
    else
    {
        dec = conv_str_dec_to_dec_method(pSrc, len);
    }
    
    return dec;
}

/**
  * @brief  十六进制字符串转十进制整数
  *
  * @note   最多转换8个字符
  *
  * @param  pSrc : 源字符串
  *
  * @param  len  : 转换数量,填0内部使用strlen()判断长度
  *
  * @retval 返回转换后的十进制整数,为0若非有意则可能返回的是错误
  */
uint32_t conv_str_hex_to_dec(char *pSrc, uint8_t len)
{
    uint8_t tmp, cnt;
    uint32_t ret;
    
    if(len == 0)
    {
        len = strlen(pSrc); /* 参数len是0则使用strlen获取长度 */
    }
    
    ASSERT_PARAM(IS_VALID_POINT(pSrc));
    ASSERT_PARAM(IS_VALID_DEC_DEC_LENGTH(len));
    
    for(cnt = 0; cnt < len; cnt++)
    {
        tmp = toupper(pSrc[cnt]) - '0'; /* 字符转大写减去字符'0' */
        /* 大于22说明超出十六进制字符范围 */
        if(tmp > 22)
        {
            return 0;
        }
        /* ABCDEF需要再减7,因为'9'到'A'之间有7个其他字符 */
        if(tmp > 9)
        {
            tmp -= 7;
        }
        /* 根据当前字符所在位置左移后累加 例:共两个字符,当前字符在第一个,则左移四位 */
        ret |= (tmp << ((len - 1 - cnt) << 2));
    }
    
    return ret;
}

/**
  * @brief  补码转十进制整数
  *
  * @param  complement : 补码
  *
  * @param  bitNum     : 补码的位数(一般有8,16,32)
  *
  * @retval 返回转换后的十进制整数
  */
int conv_complement_code_to_dec(uint32_t complement, uint8_t bitNum)
{
    ASSERT_PARAM(IS_VALID_COMP_DEC_BIT_NUM(bitNum));
    
    complement &= ((1ul << bitNum) - 1); /* 置零有效位之外的位 */
    
    /* 符号位为- */
    if(complement >> (bitNum - 1))
    {
        complement = (~(complement - 1)) & ((1ul << (bitNum - 1)) - 1); /* 减1 取反 保留有效位(原码到补码的逆操作) */
        complement = 0 - complement; /* 负数 */
    } /* 符号位为+ */
    else
    {
        /* 正数的补码是其本身 */
    }
    
    return complement;
}

/**
 * @}
 */

/**
 * @}
 */

/**
 * @}
 */
